package logic;

import commands.AvailableCommands;

import storage.RedoStorage;
import storage.UndoRedoDetails;
import storage.UndoStorage;

public class UndoRedoManager {

	private static boolean isNewCommand;

	// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// UNDO
	// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	private UndoRedoDetails getUndoLastest() {
		return UndoStorage.getLastest();
	}

	private void storeUndoDetails(UndoRedoDetails details) {
		UndoStorage.storeDetails(details);
	}

	private UndoRedoDetails peekUndoLastest() {
		return UndoStorage.peekLastest();
	}

	private void clearUndoStorage() {
		UndoStorage.clear();
	}

	// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// REDO
	// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	private UndoRedoDetails getRedoLastest() {
		return RedoStorage.getLastest();
	}

	private void storeRedoDetails(UndoRedoDetails details) {
		RedoStorage.storeDetails(details);
	}

	private UndoRedoDetails peekRedoLastest() {
		return RedoStorage.peekLastest();
	}

	private void clearRedoStorage() {
		RedoStorage.clear();
	}

	// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// MANAGE AND PASS COMMANDS TO UNDO() AND REDO()
	// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public UndoRedoDetails getAction(String caller) {
		// caller is the class that calls this, if Undo() calls, then caller =
		// "undo"
		UndoRedoDetails details_ = new UndoRedoDetails();
		AvailableCommands command_;

		if (caller.equals("undo")) {
			details_ = getUndoLastest();
			// assert !details_.equals(null);
			if (details_ == null) {
				return null;
			} else {
				command_ = AvailableCommands.valueOf(details_.getCommand()
						.toUpperCase());
				String translatedCommand = translateCommand(command_);
				details_.setCommand(translatedCommand);
				UndoRedoDetails redoDetail_ = new UndoRedoDetails();
				redoDetail_ = details_;

				storeToRedo(redoDetail_); // push to redo stack
				return details_;
			}

		} else if (caller.equals("redo")) {
			details_ = getRedoLastest();
			if (details_ == null) {
				return null;
			} else {
				command_ = AvailableCommands.valueOf(details_.getCommand()
						.toUpperCase());
				String translatedCommand = translateCommand(command_);
				details_.setCommand(translatedCommand);
				UndoRedoDetails undoDetail_ = new UndoRedoDetails();
				undoDetail_ = details_;

				storeToUndo(undoDetail_); // push to undo stack
				return details_;
			}
		}
		return details_;
	}

	private String translateCommand(AvailableCommands initCommand) {
		switch (initCommand) {

			case ADD :
				return "remove";

			case REMOVE :
				return "add";

			case EDIT :
				return "edit";

			case COMPLETE :
				return "incomplete";

			case INCOMPLETE :
				return "complete";

			default :
				return null;
		}

	}

	// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// MANAGE MEMORY - UNDO AND REDO STORAGE
	// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	// store changes - to be used in other actions, after each action
	public void storeChanges(UndoRedoDetails detail) {
		if (isNewCommand) {
			storeUndoDetails(detail);
			clearRedoStorage();
			isNewCommand = false;
		}
	}

	// pop <-> push
	// store a copy of what is pop out of storage - so that the other storage can
	// store it
	private void storeToRedo(UndoRedoDetails detail) {
		// switch initialValue with newValue
		UndoRedoDetails finalDetail = new UndoRedoDetails();
		finalDetail.setCommand(detail.getCommand());
		finalDetail.setId(detail.getId());
		finalDetail.setTask(detail.getTask());
		finalDetail.setEditingField(detail.getEditingField());
		finalDetail.setInitialValue(detail.getInitialValue());
		finalDetail.setNewValue(detail.getNewValue());

		finalDetail = rearrangeValueAndCommand(finalDetail);
		storeRedoDetails(finalDetail);
	}

	private void storeToUndo(UndoRedoDetails detail) {

		// switch initialValue with newValue
		UndoRedoDetails finalDetail = new UndoRedoDetails();
		finalDetail.setCommand(detail.getCommand());
		finalDetail.setId(detail.getId());
		finalDetail.setTask(detail.getTask());
		finalDetail.setEditingField(detail.getEditingField());
		finalDetail.setInitialValue(detail.getInitialValue());
		finalDetail.setNewValue(detail.getNewValue());

		finalDetail = rearrangeValueAndCommand(finalDetail);
		storeUndoDetails(finalDetail);
	}

	private UndoRedoDetails rearrangeValueAndCommand(UndoRedoDetails detail) {
		Object temp1 = detail.getInitialValue();
		Object temp2 = detail.getNewValue();
		UndoRedoDetails finalDetail = new UndoRedoDetails();
		finalDetail = detail;
		finalDetail.setInitialValue(temp2);
		finalDetail.setNewValue(temp1);
		return finalDetail;
	}

	public boolean setIsNewCommand() {
		return isNewCommand = true;
	}

	public boolean setNotNewCommand() {
		return isNewCommand = false;
	}

	public boolean isNewCommand() {
		return isNewCommand;
	}
}
